package track

import (
	"fmt"
	"gitee.com/general252/gortc/pkg/format"
	"gitee.com/general252/gortc/pkg/rtcsdp"
	"gitee.com/general252/gortc/pkg/rtprtcp"
	"gitee.com/general252/gortc/pkg/streammuxer"
	"github.com/pion/rtcp"
	"github.com/pion/rtp"
	"log"
	"net"
	"time"
)

type RtpRtcpWriter interface {
	WriteRTP(*rtp.Packet, net.Addr) error
	WriteRTCP([]rtcp.Packet, net.Addr) error
	Close(cause error)
}

type RtpRtcpReader interface {
	ReadPacketRTP(pkt *rtp.Packet, addr net.Addr)
	ReadPacketRTCP(packets []rtcp.Packet, addr net.Addr)
	ParsePacket(data []byte) ([]rtcp.Packet, *rtp.Packet, error)
	Close(cause error)
}

// Receiver 对网络rtp排序, 处理rtcp包
type Receiver struct {
	muxer  streammuxer.StreamMuxer
	writer RtpRtcpWriter
	media  *rtcsdp.Media
	format format.Format

	rtpReorder   *rtprtcp.RtpReorder   // 整序
	rtcpReceiver *rtprtcp.RTCPReceiver // 接收者报告

	lastReceiveRTPTime time.Time
}

func NewReceiver(muxer streammuxer.StreamMuxer, writer RtpRtcpWriter, media *rtcsdp.Media, ct format.Format) *Receiver {

	c := &Receiver{
		muxer:              muxer,
		writer:             writer,
		media:              media,
		format:             ct,
		rtpReorder:         rtprtcp.NewRtpReorder(2000),
		rtcpReceiver:       nil,
		lastReceiveRTPTime: time.Now(),
	}

	var (
		clockRate = ct.ClockRate()
		period    = time.Second * 5
		timeNow   = time.Now
	)

	receiverSSRC := media.ReceiverSSRC
	rtpReceiver, err := rtprtcp.NewRTCPReceiver(clockRate, &receiverSSRC, period, timeNow, func(packet rtcp.Packet) {
		_ = writer.WriteRTCP([]rtcp.Packet{packet}, nil)

		if time.Since(c.lastReceiveRTPTime) >= time.Second*60 {
			writer.Close(fmt.Errorf("long time not receive rtp packet"))
		}
	})
	if err != nil {
		panic(err)
	}

	c.rtcpReceiver = rtpReceiver

	c.receiver()

	return c
}

func (c *Receiver) Open() error {

	go func() {

		receiverSSRC := c.media.ReceiverSSRC
		for i := 0; i < 5; i++ {
			time.Sleep(time.Second)
			_ = c.writer.WriteRTCP([]rtcp.Packet{
				&rtcp.ReceiverReport{
					SSRC: receiverSSRC,
				},
			}, nil)
		}
	}()

	return nil
}

func (c *Receiver) Close() {
	if c.rtcpReceiver != nil {
		c.rtcpReceiver.Close()
	}
}

func (c *Receiver) receiver() {

	var (
		err          error
		rtpStreamId  = streammuxer.NewStreamIdRTP(c.media.SSRC, c.format.PayloadType())
		rtcpStreamId = streammuxer.NewStreamIdRTCP(c.media.SSRC)
	)

	// 接收rtp流, 转发给有序rtp流
	_, err = c.muxer.AddPull(rtpStreamId, streammuxer.PullInfo{
		Name: "",
		OnPacket: func(info *streammuxer.StreamInfo, data *streammuxer.StreamData) {
			switch value := data.Data.(type) {
			case *rtp.Packet:
				pkt := value
				c.readPacketRTP(pkt)
			}
		},
	})
	if err != nil {
		log.Println(err)
	}

	// 接收rtcp
	_, err = c.muxer.AddPull(rtcpStreamId, streammuxer.PullInfo{
		Name: "",
		OnPacket: func(info *streammuxer.StreamInfo, data *streammuxer.StreamData) {
			switch value := data.Data.(type) {
			case *rtcp.SenderReport:
				pkt := value
				c.readPacketRTCP(pkt)
			}
		},
	})
	if err != nil {
		log.Println(err)
	}

	// 添加有序流
	if stream, err := c.muxer.AddStream(streammuxer.StreamInfo{
		Id:   streammuxer.NewStreamIdRTPOrder(c.media.SSRC, c.format.PayloadType()),
		Name: "order-rtp-packet",
	}); err != nil {
		log.Println(err)
	} else {
		stream.GetInfo()
	}
}

func (c *Receiver) readPacketRTP(packet *rtp.Packet) {
	packets, lost := c.rtpReorder.Process(packet)
	if lost != 0 {
		// do not return
		log.Printf("loss packet: %v", lost)
	}

	now := time.Now()
	c.lastReceiveRTPTime = now

	for _, pkt := range packets {
		if pkt == nil {
			continue
		}

		if err := c.rtcpReceiver.ProcessPacket(pkt, now, c.format.PTSEqualsDTS(pkt)); err != nil {
			log.Println(err)
			continue
		}

		ntp, _ := c.rtcpReceiver.PacketNTP(pkt.Timestamp)

		// 发送有序rtp流
		streamId := streammuxer.NewStreamIdRTPOrder(c.media.SSRC, c.format.PayloadType())
		_ = c.muxer.Write(&streammuxer.StreamData{
			StreamId: streamId,
			Data:     pkt,
			Ntp:      ntp,
			Addr:     nil,
		})
	}
}

func (c *Receiver) readPacketRTCP(sr *rtcp.SenderReport) {
	c.rtcpReceiver.ProcessSenderReport(sr, time.Now())
}

func (c *Receiver) PacketNTP(pkt *rtp.Packet) (time.Time, bool) {
	return c.rtcpReceiver.PacketNTP(pkt.Timestamp)
}

func (c *Receiver) Media() *rtcsdp.Media {
	return c.media
}

func (c *Receiver) Format() format.Format {
	return c.format
}

func (c *Receiver) Equal(ssrc uint32, pt uint8) bool {
	if c.media.SSRC == ssrc && c.format.PayloadType() == pt {
		return true
	}
	return false
}
